<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <base data-ice="baseUrl" href="../../">
  <title data-ice="title">source/Module.js | amd-bundle</title>
  <link type="text/css" rel="stylesheet" href="css/style.css">
  <link type="text/css" rel="stylesheet" href="css/prettify-tomorrow.css">
  <script src="script/prettify/prettify.js"></script>
  <script src="script/manual.js"></script>
<meta name="description" content="A dual-use tool for bundling up AMD modules, which is much easier to use than r.js with Almond or AMDclean"><meta property="twitter:card" content="summary"><meta property="twitter:title" content="amd-bundle"><meta property="twitter:description" content="A dual-use tool for bundling up AMD modules, which is much easier to use than r.js with Almond or AMDclean"></head>
<body class="layout-container" data-ice="rootContainer">

<header>
  <a href="./">Home</a>
  
  <a href="identifiers.html">Reference</a>
  <a href="source.html">Source</a>
  <a href="test.html" data-ice="testLink">Test</a>
  <div class="search-box">
  <span>
    <img src="./image/search.png">
    <span class="search-input-edge"></span><input class="search-input"><span class="search-input-edge"></span>
  </span>
    <ul class="search-result"></ul>
  </div>
<a style="position:relative; top:3px;" href="https://github.com/TechQuery/AMD_bundle.js"><img width="20px" src="./image/github.png"></a></header>

<nav class="navigation" data-ice="nav"><div>
  <ul>
    
  <li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/source/Module.js~Module.html">Module</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/source/Package.js~Package.html">Package</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-generate">generate</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getNPMFile">getNPMFile</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getNPMIndex">getNPMIndex</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getNPMPackage">getNPMPackage</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-merge">merge</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-outPackage">outPackage</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-DependencyMap">DependencyMap</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-NameMap">NameMap</a></span></span></li>
</ul>
</div>
</nav>

<div class="content" data-ice="content"><h1 data-ice="title">source/Module.js</h1>
<pre class="source-code line-number raw-source-code"><code class="prettyprint linenums" data-ice="content">import {EventEmitter} from &apos;events&apos;;

import {dirname, join} from &apos;path&apos;;

import {readFileSync} from &apos;fs&apos;;

import * as Utility from &apos;./utility&apos;;

import { toES_5 } from &apos;@tech_query/node-toolkit&apos;;


const AMD_CJS = [&apos;require&apos;, &apos;exports&apos;, &apos;module&apos;];

/**
 * Key for the replacement of a module name, and value for a {@link RegExp}
 *
 * @typedef {Object} NameMap
 */

/**
 * Key for module path &amp; value for local variable
 *
 * @typedef {Object} DependencyMap
 */


/**
 * CommonJS or AMD module
 */
export default  class Module extends EventEmitter {
    /**
     * @param {string}  name               - Path of this module
     * @param {string}  [path=&apos;.&apos;]         - Root path of the package which this module belongs to
     * @param {boolean} [includeAll=false] - Treat NPM modules as CommonJS modules
     * @param {NameMap} [nameMap]          - Map to replace some dependencies to others
     */
    constructor(name,  path = &apos;.&apos;,  includeAll = false,  nameMap) {
        /**
         * Path of this module
         *
         * @type {string}
         */
        super().name = name.replace(/\\/g, &apos;/&apos;);

        /**
         * Directory path of this module
         *
         * @type {string}
         */
        this.base = dirname( this.name );

        /**
         * Full name of this module file
         *
         * @type {string}
         */
        this.fileName = join(path, `${this.name}.js`);

        /**
         * @type     {Object}
         * @property {DependencyMap} compile - Compile-time dependency from AMD
         * @property {DependencyMap} runtime - Runtime dependency from CommonJS
         * @property {DependencyMap} outside - Outside dependency from NPM
         */
        this.dependency = {
            compile:  { },
            runtime:  { },
            outside:  includeAll ? null : { }
        };

        /**
         * CLI engine (Hash bang)
         *
         * @type {String}
         */
        this.CLI = &apos;&apos;;

        /**
         * @type {NameMap}
         */
        this.nameMap = nameMap  ||  { };
    }

    /**
     * @param {string} name - Name of a module
     *
     * @return {string}
     */
    static identifierOf(name) {  return  name.replace(/\W+/g, &apos;_&apos;);  }

    /**
     * Identifier of this module in JS code
     *
     * @type {string}
     */
    get identifier() {  return  Module.identifierOf( this.name );  }

    /**
     * Paths of all the dependency needed to be bundled
     *
     * @type {string[]}
     */
    get dependencyPath() {

        return  Object.keys( this.dependency.compile ).concat(
            Object.keys( this.dependency.runtime )
        );
    }

    /**
     * @protected
     *
     * @return {?string} Entry file path of this module in `./node_modules/`
     */
    searchNPM() {

        for (let method  of  [&apos;getNPMFile&apos;, &apos;getNPMPackage&apos;, &apos;getNPMIndex&apos;]) {

            let path;

            if (path = Utility[method]( this.name ))  return path;
        }
    }

    /**
     * @protected
     *
     * @return {string} Original source code of this module
     */
    load() {

        this.source = readFileSync(
            ((! this.dependency.outside)  &amp;&amp;  Utility.outPackage( this.name ))  ?
                this.searchNPM() : this.fileName
        ) + &apos;&apos;;

        this.source = this.source.replace(
            /^#!.+[\r\n]+/,  engine =&gt; (this.CLI = engine.trim()) &amp;&amp; &apos;&apos;
        );

        if (/^(import|export) /m.test( this.source ))
            this.source = toES_5(this.source, this.fileName, true);

        return  this.source = this.source.replace(/\r\n/g, &apos;\n&apos;);
    }

    /**
     * @param {string} module - Module name from source code
     *
     * @emits {ReplaceEvent}
     *
     * @return {?string} New module name if `module` is matched in the name map
     */
    mapName(module) {

        for (let name in this.nameMap) {

            let result = module.replace(this.nameMap[ name ],  name);

            if (result !== module) {

                this.emit(&apos;replace&apos;, module, result);  return result;
            }
        }
    }

    /**
     * Add a depended module of this module
     *
     * @protected
     *
     * @param {string} type      - `compile` for AMD &amp; `runtime` for CJS
     * @param {string} name      - Name of a module
     * @param {string} [varName] - Variable name of a module in another module
     *
     * @return {?String} Replaced module name
     */
    addChild(type, name, varName) {

        if ((type === &apos;compile&apos;)  &amp;&amp;  AMD_CJS.includes( name ))  return;

        name = Utility.outPackage( name )  ?  name  :  (
            &apos;./&apos;  +  join(this.base, name).replace(/\\/g, &apos;/&apos;)
        );

        const newName = this.mapName( name );  name = newName || name;

        if (this.dependency.outside  &amp;&amp;  (name[0] !== &apos;.&apos;))  type = &apos;outside&apos;;

        this.dependency[ type ][ name ] = varName  ||  Module.identifierOf( name );

        return newName;
    }

    /**
     * @protected
     *
     * @return {DependencyMap} Compile-time dependency
     */
    parseAMD() {

        this.source = this.source.replace(
            /define\((?:\s*\[([\s\S]*?)\]\s*,)?\s*function\s*\(([\s\S]*?)\)\s*\{([\s\S]+)\}\s*\);?/,
            (_, modName, varName, body) =&gt; {

                var index = 0;  varName = varName.trim().split( /\s*,\s*/ );

                (modName || &apos;&apos;).replace(
                    /(?:&apos;|&quot;)(.+?)(?:&apos;|&quot;)/g,
                    (_, name)  =&gt;  {

                        this.addChild(&apos;compile&apos;, name, varName[index]),  index++;
                    }
                );

                return  body.replace(/^\n([\s\S]+)\n$/, &apos;$1&apos;);
            }
        );

        return this.dependency.compile;
    }

    /**
     * @protected
     *
     * @return {DependencyMap} Runtime dependency
     */
    parseCJS() {

        this.source = this.source.replace(
            /((?:var|let|const)\s+\w+?\s*=.*?)?require\(\s*(?:&apos;|&quot;)(.+?)(?:&apos;|&quot;)\s*\)/mg,
            (_, assign, modName)  =&gt;
                `${assign || &apos;&apos;}require(&apos;${
                    this.addChild(&apos;runtime&apos;, modName)  ||  modName
                }&apos;)`
        );

        return this.dependency.runtime;
    }

    /**
     * @return {string} Factory code of this parsed module
     */
    parse() {

        this.load();

        this.parseAMD();

        this.parseCJS();

        return  this.source = `function (${

            Object.values( this.dependency.compile ).concat( AMD_CJS ).join(&apos;, &apos;)
        }) {${
            this.source
        }}`;
    }

    /**
     * @return {string} Factory code of this parsed module
     */
    toString() {

        return  (&apos;source&apos; in this)  ?  (this.source + &apos;&apos;)  :  &apos;&apos;;
    }
}
</code></pre>

</div>

<footer class="footer">
  Generated by <a href="https://esdoc.org">ESDoc<span data-ice="esdocVersion">(1.1.0)</span><img src="./image/esdoc-logo-mini-black.png"></a>
</footer>

<script src="script/search_index.js"></script>
<script src="script/search.js"></script>
<script src="script/pretty-print.js"></script>
<script src="script/inherited-summary.js"></script>
<script src="script/test-summary.js"></script>
<script src="script/inner-link.js"></script>
<script src="script/patch-for-local.js"></script>
</body>
</html>
